/** @file    PersistenceManager.cpp
 *  @author  Alessandro Polo
 *  @version $Id: PersistenceManager.cpp 2831 2010-08-02 22:15:14Z alex $
 *  @brief
 * File containing methods for the wosh::PersistenceManager class.
 * The header for this class can be found in PersistenceManager.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/PersistenceManager.h>
 #include <core/ObjectAllocator.h>
 #include <core/ObjectFactory.h>
 #include <core/WoshKernel.h>
 #include <core/SystemError.h>
 #include <core/Fact.h>
 #include <core/MethodsCommon.h>
 #include <core/MessageFilter.h>
 #include <core/MessageProcessingCommon.h>
 #include <core/List.h>
 #include <core/Table.h>
 #include <core/Utilities.h>
 #include <core/DataModels.h>


using namespace std;
namespace wosh {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER_INTERFACE(wosh::PersistenceDb, "", 1.00, _static_PersistenceDb )
// WOSH_REGISTER(wosh::PersistenceDbGeneric, "wosh::PersistenceDb", 1.00, _static_PersistenceDbGeneric )

PersistenceDb::PersistenceDb()
	: Object() {

	Properties.set( _PersistenceDb_KEY_Protocol,		"", Permission::RW_R__R__() );
	Properties.set( _PersistenceDb_KEY_ProtocolVersion,	0.0, Permission::RW_R__R__() );
	Properties.set( _PersistenceDb_KEY_EncodeCompact,	true, Permission::RW_R__R__() );

	Properties.set( _PersistenceDb_KEY_FileInput,	"", Permission::RW_R__R__() );
	Properties.set( _PersistenceDb_KEY_FileOutput,	"", Permission::RW_R__R__() );

	Properties.set( _PersistenceDb_KEY_LastLoadTS,	0, Permission(Permission::Read) );
	Properties.set( _PersistenceDb_KEY_LastSaveTS,	0, Permission(Permission::Read) );

	if ( PersistenceManager::getInstance() != NULL )
		PersistenceManager::getInstance()->persistence_db_action( 1, this);
 }

PersistenceDb::~PersistenceDb() {
	if ( PersistenceManager::getInstance() != NULL )
		PersistenceManager::getInstance()->persistence_db_action( 0, this);
 }

WRESULT PersistenceDb::setLog( LogContext& Log ) {
	this->log = &Log;
	return WRET_OK;
 }

WRESULT PersistenceDb::setProtocol( const std::string& protocol, double version ) {
	Properties.update( _PersistenceDb_KEY_Protocol,	protocol );
	Properties.update( _PersistenceDb_KEY_ProtocolVersion, version );
	return WRET_OK;
 }
WRESULT PersistenceDb::setEncodeCompact( bool compact_enabled ) {
	Properties.update( _PersistenceDb_KEY_EncodeCompact, compact_enabled );
	return WRET_OK;
 }
WRESULT PersistenceDb::setFileInput( const std::string& wosh_path ) {
	Properties.update( _PersistenceDb_KEY_FileInput, wosh_path );
	return WRET_OK;
 }
WRESULT PersistenceDb::setFileOutput( const std::string& wosh_path ) {
	Properties.update( _PersistenceDb_KEY_FileOutput, wosh_path );
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<PersistenceDb>* PersistenceDb::getDataFields() {
	DataFieldCollector<PersistenceDb>* fields = new DataFieldCollector<PersistenceDb>();
	fields->add<const char*,Variant>(&PersistenceDb::getClassName, "Type", 0);
//	fields->add<const char*,Variant>(&PersistenceDb::getProtocol, "MappedObject", 1);
	return fields;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Gamma singleton! static reference is allocated and maintained by WoshKernel
extern "C" {
	PersistenceManager* PersistenceManager::getInstance() { 
		if ( WoshKernel::getInstance() == NULL ) return NULL;
		return &WoshKernel::getInstance()->persistence();
	}
};

 // register as abstract because it is a singleton:
 WOSH_REGISTER_INTERFACE(wosh::PersistenceManager, "wosh::WoshModule", 0.01, _static_PersistenceManager )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

PersistenceManager::PersistenceManager( const WoshKernel* parent )
	: WoshModule(parent, _PersistenceManager_NAME, _PersistenceManager_URI) {

Log.setLevel( LOG_VERBOSE );

	this->ProtocolsVirtualURI.setParent( Object::getURI() );
	this->ProtocolsVirtualURI.setName( "Protocols" );
	this->ProtocolsVirtualURI.registerGlobal();
	this->DataBasesVirtualURI.setParent( Object::getURI() );
	this->DataBasesVirtualURI.setName( "DB" );
	this->DataBasesVirtualURI.registerGlobal();

	Log(LOG_DEBUG, " Initializing Properties.." );
	Properties.set( _PersistenceManager_KEY_Encoders_Count,	0, Permission( Permission::Read ) );

	Log(LOG_DEBUG, " Registering Methods.." );
	MethodRequest* mmList = Methods.create<MethodRequest>( _METHOD_List, "List", Permission(Permission::RX) );
	mmList->setMethod( this, (MethodRequestPtr)&PersistenceManager::mmDoList );

	MethodList* mmListEncoderProtocols = Methods.create<MethodList>( _PersistenceManager_METHOD_Protocols_list, "List Protocols", Permission::R_XR_XR__() );
	mmListEncoderProtocols->setDataFieldExtractor( DataFieldExtractor<EncoderProtocol>::createFor< DataAdapterListT<EncoderProtocol> >(this->Protocols, "Encoder Protocols") );

	MethodList* mmListDataBases = Methods.create<MethodList>( _PersistenceManager_METHOD_DataBases_list, "List DataBases", Permission::R_XR_XR__() );
	mmListDataBases->setDataFieldExtractor( DataFieldExtractor<PersistenceDb>::createFor< DataAdapterListT<PersistenceDb> >(this->DataBases, "DataBases") );

	MethodMessageResponse* mmLoadProtocol = Methods.create<MethodMessageResponse>( _PersistenceManager_METHOD_LoadProtocol, "Load a Protocol", Permission::RW_RW_R__() );
	mmLoadProtocol->setMethod( this, (MethodMessageResponsePtr)&PersistenceManager::mmDoLoadProtocol );

	MethodRequest* mmListSupportedProtocols = Methods.create<MethodRequest>( _PersistenceManager_METHOD_ListSupportedProtocols, "List supported Protocols", Permission(Permission::RX) );
	mmListSupportedProtocols->setMethod( this, (MethodRequestPtr)&PersistenceManager::mmDoListSupportedProtocols );
 }

PersistenceManager::~PersistenceManager() {
	Log(LOG_DEBUG, ":~PersistenceManager() Destroying.." );
	Log(LOG_VERBOSE, ":~PersistenceManager() Freeing Protocols [%d]..", this->Protocols.count() );
	this->Protocols.clear();
	Log(LOG_VERBOSE, " Destroyed." );
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT PersistenceManager::onKernelInitializing() {
	WRESULT ret = WoshModule::onKernelInitializing();

	if ( Properties.exists(_PersistenceManager_KEY_AutoLoadProtocols) ) {
		vector<string> protos;
		string protoStr = Properties.getValueOf(_PersistenceManager_KEY_AutoLoadProtocols).toString();
		Utilities::splitString(protoStr, ";", protos, false, true);
		WRESULT ret_c = WRET_OK;
		std::vector<std::string>::iterator it;
		for ( it=protos.begin(); it!=protos.end(); ++it ) {
			EncoderProtocol* net_proto = loadProtocol(*it);
			if ( net_proto == NULL ) {
				ret += WRET_ERR_PARAM;
				continue;
			 }
			ret_c = installProtocol(net_proto, true);
			ret += ret_c;
		 }
	 }

	return ret;
 }

WRESULT PersistenceManager::onKernelStopped() {
	WRESULT ret = WRET_OK;
	this->Protocols.free();
	ret = WoshModule::onKernelStopped();
	return ret;
 }

void PersistenceManager::busMessage( const Message& message, const Bus* ) {
	if ( message.isEmpty() ) return;
	if ( !message.getContent()->isRequest() ) return;

	// manage messages for myself
	Message* reply = NULL;
	if ( MessageFilter::isMessageTarget(message, this) ) {
		reply = MPC_busMessageRequest( message, Methods, Log );
		if ( reply == NULL ) return;
		reply->setSource( this );
		BusCore.postMessage(reply);
		return;
	 }
	else if ( !message.getDestination().isChildOf(this->getURI(), false) )
		return;	

	string target_name = message.getDestination().getName();
	const Request* request = message.getContent()->asRequest();

	if ( target_name == "Protocols" ) {
		if ( request->getMethod() == _METHOD_List ) {
			Method* method = Methods.find(_PersistenceManager_METHOD_Protocols_list);
			if ( method == NULL ) {
				Log(LOG_WARNING, ":busMessage() FAILED : Method '%s' not found", request->getMethod().c_str() );
				reply = message.replyTo( request->replyResponse(WRET_ERR_PARAM, "Method not found!") );
			 }
			else
				reply = method->exec( &message );
		 }
		else {
			Log(LOG_WARNING, ":busMessage() FAILED : Method '%s' not found", request->getMethod().c_str() );
			reply = message.replyTo( request->replyResponse(WRET_ERR_PARAM, "Method not found!") );
		 }
		reply->setSource( this );
		reply->setSource( this->ProtocolsVirtualURI ); // overwrite uri!
	 }
	else if ( target_name == "DB" ) {
		if ( request->getMethod() == _METHOD_List ) {
			Method* method = Methods.find(_PersistenceManager_METHOD_DataBases_list);
			if ( method == NULL ) {
				Log(LOG_WARNING, ":busMessage() FAILED : Method '%s' not found", request->getMethod().c_str() );
				reply = message.replyTo( request->replyResponse(WRET_ERR_PARAM, "Method not found!") );
			 }
			else
				reply = method->exec( &message );
		 }
		else {
			Log(LOG_WARNING, ":busMessage() FAILED : Method '%s' not found", request->getMethod().c_str() );
			reply = message.replyTo( request->replyResponse(WRET_ERR_PARAM, "Method not found!") );
		 }
		reply->setSource( this );
		reply->setSource( this->DataBasesVirtualURI ); // overwrite uri!
	 }

	if ( reply != NULL ) {
		BusCore.postMessage(reply);
		return;
	 }

//	if ( !message.getDestination().isChildOf(this->getURI(), false) )
//		return;
	if ( message.getDestination().getPath().size() < 2 )
		return;
	if ( message.getDestination().getPath().at(1) == "Protocols" ) {
		Log(LOG_VERBOSE, ":busMessage() = Message-Request for Child '%s'", target_name.c_str() );
		this->Protocols.transactionBeginRead(); // following operation won't ever really add/delete a channel item
		MPC_mmDo_InContainer<EncoderProtocol>(message, this->Protocols, Log, BusCore);
		this->Protocols.transactionEnd();
	 }
	else if ( message.getDestination().getPath().at(1) == "DB" ) {
		Log(LOG_VERBOSE, ":busMessage() = Message-Request for Child '%s'", target_name.c_str() );
		this->DataBases.transactionBeginRead(); // following operation won't ever really add/delete a channel item
//		MPC_mmDo_InContainer<PersistenceDb>(message, this->DataBases, Log, BusCore);
		this->DataBases.transactionEnd();
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT PersistenceManager::installProtocol( EncoderProtocol* encoder_protocol, bool raise_event ) {
	if ( encoder_protocol == NULL ) return WRET_ERR_PARAM;
	Log(LOG_INFO, ":installProtocol(%s) : Registering Protocol..",  encoder_protocol->getName().c_str() );

	this->Protocols.transactionBeginWrite();
	if ( this->Protocols.exists(encoder_protocol) ) {
		this->Protocols.transactionEnd();
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "installProtocol", "FAILED %s already registered!", encoder_protocol->getName().c_str() );
		return WRET_ERR_PARAM;
	 }
	encoder_protocol->getURI().setParent( this->ProtocolsVirtualURI );
	encoder_protocol->getURI().registerGlobal();
	encoder_protocol->setPermission( this->getPermission(), Permission::Overwrite_All, true );
	encoder_protocol->setParentObject(this);
	encoder_protocol->setListener(this);
	encoder_protocol->init();

//	Log(LOG_INFO, ":installProtocol(%s) : Loading default settings..",  encoder_protocol->getName().c_str() );
//	WoshKernel* kernel = WoshKernel::getInstance();
//	if ( kernel != NULL )
//		encoder_protocol->getConfiguration().intersect( kernel->SettingsDefault.getSettingsOf( encoder_protocol->getName() ), true, false );

	this->Protocols.push_back(encoder_protocol);
	Properties.update( _PersistenceManager_KEY_Encoders_Count, Protocols.size() );

	Fact* fact =NULL;
	if ( raise_event )
		fact = new PersistenceManager_ProtocolUpdated(encoder_protocol->getProtocol(), 1 );

	this->Protocols.transactionEnd();
	if ( fact != NULL ) {
		Message* msg_event = new Message(fact);
		msg_event->setDestinationBroadcast(true);
		signMessage(msg_event);
		BusCore.postMessage(msg_event);
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

EncoderProtocol* PersistenceManager::loadProtocol( const string& encoder_protocol, double version ) {
	Log(LOG_VERBOSE, ":loadProtocol() : Requesting ObjectFactory to allocate [%s,%g]..", encoder_protocol.c_str(), version );
	EncoderProtocol* encProto = ObjectFactory::createTypeOf<EncoderProtocol>(encoder_protocol, version);
	if ( encProto == NULL ) {
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "loadProtocol", "FAILED (NULL) creating Protocol %s!", encoder_protocol.c_str() );
		return NULL;
	 }
	encProto->setPermission( this->getPermission(), Permission::Overwrite_All, true );
	return encProto;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

EncoderProtocol* PersistenceManager::getProtocol_( const char* protocol_name,  double protocol_version, bool strict ) {
	if ( getInstance() == NULL ) return NULL;
	tEncoderProtocolList::Iterator it;
	const tEncoderProtocolList::ConstIterator it_end = getInstance()->Protocols.end();
	for ( it=getInstance()->Protocols.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( strict ) {
			if ( strcmp( (*it)->getProtocol(), protocol_name) != 0 ) continue;
			if ( protocol_version != 0.0 && (*it)->getProtocolVersion() != protocol_version ) continue;
			return *it;
		 }
		if ( strcmp( (*it)->getProtocol(), protocol_name) != 0 && strcmp( (*it)->getProtocol(), protocol_name) != 1 ) continue;
		if ( protocol_version != 0.0 && (*it)->getProtocolVersion() != protocol_version ) continue;
		return *it;
	 }
	return NULL;
 }

EncoderProtocol* PersistenceManager::getProtocolByType_( const char* class_name ) {
	if ( getInstance() == NULL ) return NULL;
	if ( class_name == NULL ) return NULL;
	tEncoderProtocolList::Iterator it;
	const tEncoderProtocolList::ConstIterator it_end = getInstance()->Protocols.end();
	for ( it=getInstance()->Protocols.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( strcmp( (*it)->getClassName(), class_name) != 0 ) continue;
		return *it;
	 }
	return NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

PersistenceDb* PersistenceManager::createDb( const char* protocol_name, double protocol_version ) {
	if ( getInstance() == NULL ) return NULL;
	EncoderProtocol* encProto = getInstance()->getProtocol_(protocol_name, protocol_version);
	if ( encProto == NULL ) return NULL;
	return encProto->createDb();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void PersistenceManager::encoder_protocol_db_action( const std::string& db_name, EncoderProtocol* source ) {
	(void)db_name; (void)source;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void PersistenceManager::persistence_db_action( int state, PersistenceDb* source ) {
	if ( state == 0 ) {
		Log(LOG_INFO, ":persistence_db_action() : Destroy DB" );
		this->DataBases.transactionBeginWrite();
		this->DataBases.pop(source);
		this->DataBases.transactionEnd();
	 }
	else if ( state == 1 ) {
		Log(LOG_INFO, ":persistence_db_action() : Created DB" );
		this->DataBases.transactionBeginWrite();
		this->DataBases.push_back(source);
		this->DataBases.transactionEnd();
	 }

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// METHODS

Response* PersistenceManager::mmDoList( const Request* request ) {
	if ( request == NULL ) return NULL;
	string option = request->getArgument().toString();
	Log(LOG_DEBUG, ":mmDoList(%s)", option.c_str() );
	if ( option == "s" || option == "short" ) {
		List* objs = new List(2);
		objs->push_back<Variant>( "Protocols" );
		objs->push_back<Variant>( "DB" );
		return request->replyResponse(WRET_OK, objs);
	 }
	else {
		Table* tbl = new Table( 2, 3, true );
		tbl->setTableName("PersistenceManager children");
		tbl->setHeaderHorizontal("Name", 0);
		tbl->setHeaderHorizontal("URI", 1);
		tbl->setHeaderHorizontal("Count", 2);
		unsigned int iRow = 0;
		tbl->set<Variant>( "Protocols", iRow, 0);
		tbl->set( this->ProtocolsVirtualURI.clone(), iRow, 1);
		tbl->set<Variant>( this->Protocols.size(), iRow, 2);
		++iRow;
		tbl->set<Variant>( "DB", iRow, 0);
		tbl->set( this->DataBasesVirtualURI.clone(), iRow, 1);
		tbl->set<Variant>( this->DataBases.size(), iRow, 2);

		++iRow;
		return request->replyResponse(WRET_OK, tbl);
	 }
 }

Response* PersistenceManager::mmDoListSupportedProtocols( const Request* request ) {
	if ( request == NULL ) return NULL;
	string option = request->getArgument().toString();
	Log(LOG_DEBUG, ":mmDoListSupportedProtocols(%s)", option.c_str() );
	std::vector<ObjectTypeInfo> class_list;
	WRESULT ret = ObjectFactory::findChildsOf( class_list, EncoderProtocol::className(), 0.0, true );
	if ( WFAILED(ret) )
		return request->replyResponse(WRET_ERR_INTERNAL, "Failed getting Type-list");
	std::vector<ObjectTypeInfo>::const_iterator it;
	if ( option == "s" || option == "short" ) { 
		List* objs = new List(class_list.size());
		for ( it=class_list.begin(); it!=class_list.end(); ++it ) {
			objs->push_back<Variant>( (*it).name );
		 }
		return request->replyResponse(WRET_OK, objs);
	 }
	else {
		Table* tbl = new Table( class_list.size(), 4, true );
		tbl->setTableName("Supported EncoderProtocol");
		tbl->setHeaderHorizontal("Name", 0);
		tbl->setHeaderHorizontal("Main Interface", 1);
		tbl->setHeaderHorizontal("Version", 2);
		tbl->setHeaderHorizontal("Installed", 3);
		unsigned int iRow = 0;
		this->Protocols.transactionBeginRead();
		for ( it=class_list.begin(); it!=class_list.end(); ++it, ++iRow ) {
			tbl->set<Variant>( (*it).name, iRow, 0);
			tbl->set<Variant>( (*it).parent, iRow, 1);
			tbl->set<Variant>( (*it).version, iRow, 2);
			if ( getProtocolByType_((*it).name.c_str()) != NULL )
				tbl->set( new Variant(true), iRow, 3);
			else
				tbl->set( new Variant(false), iRow, 3);
		 }
		this->Protocols.transactionEnd();
		return request->replyResponse(WRET_OK, tbl);
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Response* PersistenceManager::mmDoLoadProtocol( const Message* requestMessage ) {
	if ( requestMessage == NULL || requestMessage->isEmpty() ) return NULL;
	if ( !requestMessage->getContent()->isRequest() ) return NULL;
	//const Request* request = requestMessage->getContent()->asRequest();
	///@todo check rigths
	//Variant dBundleType;
	return NULL;
 }


///////////////////////////////////////////////////////////////////////////////////////////////////// METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


int PersistenceManager::getEncoderProtocolsFor( std::vector<std::string>& encoder_protocols, const char* classname, double version ) {
	if ( getInstance() == NULL ) return -1;
	getInstance()->Protocols.transactionBeginRead();
	tEncoderProtocolList::Iterator it;
	const tEncoderProtocolList::ConstIterator it_end = getInstance()->Protocols.end();
	for ( it=getInstance()->Protocols.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( !(*it)->isSupported(classname, version) ) continue;
		encoder_protocols.push_back( (*it)->getProtocol() );
	 }
	getInstance()->Protocols.transactionEnd();
	return encoder_protocols.size();
 }

int64 PersistenceManager::serializeTo( const ISerializable* object, const char* protocol, char* buffer, int64 buffer_size, int encoder_options ) {
	if ( getInstance() == NULL ) return -1;
	if ( object == NULL ) return -1;
	if ( buffer == NULL ) return -1;
	getInstance()->Log(LOG_DEBUG, ":serializeTo(%s, %s, %"PRId64", %d)", object->getClassName(), protocol, buffer_size, encoder_options );
	getInstance()->Protocols.transactionBeginRead();
	EncoderProtocol* enc_proto = getProtocol_(protocol);
	int64 size = -2;
	if ( enc_proto != NULL )
		size = enc_proto->serializeTo(object, buffer, buffer_size, encoder_options);
	getInstance()->Protocols.transactionEnd();
	return size;
 }

int64 PersistenceManager::deserializeFrom( ISerializable* object, const char* protocol, const char* buffer, int64 buffer_size ) {
	if ( getInstance() == NULL ) return -1;
	if ( object == NULL ) return -1;
	if ( buffer == NULL ) return -1;
	getInstance()->Log(LOG_DEBUG, ":deserializeFrom(%s, %s, %"PRId64")", object->getClassName(), protocol, buffer_size );
	getInstance()->Protocols.transactionBeginRead();
	EncoderProtocol* enc_proto = getProtocol_(protocol);
	int64 size = -2;
	if ( enc_proto != NULL )
		size = enc_proto->deserializeFrom(object, buffer, buffer_size);
	getInstance()->Protocols.transactionEnd();
	return size;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT PersistenceManager::serializeTo( const PersistenceDb* object ) {
	if ( getInstance() == NULL ) return WRET_ERR_INTERNAL;
	if ( object == NULL ) return WRET_ERR_PARAM;
	//getInstance()->Log(LOG_VERBOSE, ":serializeTo(%s, %s)", object->getClassName(), object->getProtocol().c_str() );
	//getInstance()->Protocols.transactionBeginRead();
	//EncoderProtocol* enc_proto = getProtocol_(object->getProtocol().c_str(), object->getProtocolVersion());
	//enc_proto->ser
	WRESULT ret = WRET_ERR_INTERNAL;
//	if ( enc_proto != NULL )
//		ret = enc_proto->serializeTo(object);
	//getInstance()->Protocols.transactionEnd();
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER(wosh::PersistenceManager_ProtocolUpdated, "wosh::Fact", 1.0, _static_PersistenceManager_ProtocolUpdated )

PersistenceManager_ProtocolUpdated::PersistenceManager_ProtocolUpdated( const std::string& protocol )
	: Fact( _PersistenceManager_EVENT_ProtocolUpdated ) {
	setData( new Variant( protocol ) );
 }

PersistenceManager_ProtocolUpdated::PersistenceManager_ProtocolUpdated( const std::string& protocol, short protocol_action )
	: Fact( _PersistenceManager_EVENT_ProtocolUpdated ) {
	List* args = List::createFrom<Variant>( protocol, (int)protocol_action );
	setData(args);
 }

std::string PersistenceManager_ProtocolUpdated::getProtocolName() const {
	const Variant* var = getDataItem<Variant>(0);
	if ( var == NULL ) return "";
	if ( var->isString() ) return var->asString();
	return var->toString();
 }

short PersistenceManager_ProtocolUpdated::getProtocolAction() const {
	const Variant* var = getDataItem<Variant>(1);
	if ( var == NULL ) return 1;
	if ( var->isNumeric() ) return 1;
	return var->toInteger(1);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


}; // namespace wosh
